class ToolDraw {
	rankdir = 'LR'
	rowGap = 100
	rowPadding = 20
	colGap = 100
	colPadding = 20
	align = 'UL'
	endID = '-1'

	nodeMap = new Map()
	edgeMap = new Map()

	nodes = []

	nodeTree = []

	// 节点串联后的通道路线 eq. [nodeid, nodeid, nodeid]
	channelRoutes = []

	constructor(option = {}) {
		this.rankdir = option.rankdir ?? 'LR'
		this.rowGap = option.rowGap ?? this.rowGap
		this.rowPadding = option.rowPadding ?? this.rowPadding
		this.colGap = option.colGap ?? this.colGap
		this.colPadding = option.colPadding ?? this.colPadding
		this.align = option.align ?? 'UL'
		this.endID = option.endID ?? '-1'
	}

	setEnd(id) {
		this.endID = id
	}

	setNode(id, node) {
		const baseNode = {
			id,
			from: [],
			to: [],
			row: 0, // 当前 node 占几列的位置
			col: 0, // 当前 node 占几行的位置
			x: 0,
			y: 0,
			width: 0,
			height: 0
		}

		this.nodeMap.set(id, {
			...baseNode,
			...this.nodeMap.get(id),
			...node
		})
	}

	getNodes() {
		return this.nodes.map(node => node.id)
	}

	getNode(id) {
		return this.nodeMap.get(id)
	}

	/**
	 * 配置连接线的数据
	 * @param {Any} source 起始的节点 id
	 * @param {Any} target 链接的节点 id
	 */
	setEdge(source, target) {
		if (!this.edgeMap.has(source)) {
			this.edgeMap.set(source, [target])
		} else {
			this.edgeMap.get(source).push(target)
		}

		if (this.nodeMap.has(source)) {
			this.nodeMap.get(source).to.push(target)
		} else {
			this.nodeMap.set(source, {
				from: [],
				to: [target]
			})
		}

		if (this.nodeMap.has(target)) {
			this.nodeMap.get(target).from.push(source)
		} else {
			this.nodeMap.set(target, {
				from: [source],
				to: []
			})
		}
	}

	setRoutes(routes) {
		this.channelRoutes = [...routes]
	}

	clear() {
		this.nodeTree = []
		this.channelRoutes = []
		this.nodeMap.clear()
		this.edgeMap.clear()
	}

	// 递归生成节点路线的 tree 数据
	createDeepNodeTree(node, edgeMap) {
		if (!edgeMap.has(node.id)) {
			return []
		}

		const edgeList = edgeMap.get(node.id) || []

		return edgeList.map((targetID) => {
			const child = {
				id: targetID,
				root: [...node.root, targetID],
				hasChild: false,
				children: []
			}

			child.children = this.createDeepNodeTree(child, edgeMap)
			child.hasChild = !!child.children.length

			return child
		})
	}

	loopNodeQueue(nodeTree, callback) {
		for (const node of nodeTree) {
			if (callback(node)) break

			if (node.children.length) {
				this.loopNodeQueue(node.children, callback)
			}
		}
	}

	formatNodeAssign() {
		this.nodeTree = []
		this.channelRoutes = []
		const nodeEntries = this.nodeMap.entries()

		// 寻找所有的起始节点，生成一个路线的 tree
		for (let i = 0; i < this.nodeMap.size; i++) {
			const [nodeID, extra] = nodeEntries.next().value

			if (!extra.from.length) {
				this.nodeTree.push({
					id: nodeID,
					root: [nodeID],
					hasChild: false,
					children: []
				})
			}
		}

		this.nodeTree.forEach((node) => {
			if (!this.edgeMap.has(node.id)) {
				return
			}

			node.children = this.createDeepNodeTree(node, this.edgeMap)
			node.hasChild = !!node.children.length
		})

		// console.log('🚀 ~ ToolDraw ~ this.nodeTree.forEach ~ this.nodeTree:', this.nodeTree)

		// 根据路线 tree 的末尾节点，获取串联节点后的通道路线
		this.loopNodeQueue(this.nodeTree, (node) => {
			if (!node.hasChild) {
				this.channelRoutes.push(node.root)
			}
		})

		// console.log('🚀 ~ ToolDraw ~ this.loopNodeQueue ~ this.channelRoutes:', this.channelRoutes)
	}

	/**
	 * 节点添加连接线并且自动布局
	 */
	layout() {
		this.formatNodeAssign()

		// const inputArrays = [[4, 3, 6, 7], [1, 2, 3, 7], [1, 5, 3, 8, 9, 7]]
		// const inputArrays = [[1, 4, 3, 6, 7], [1, 2, 3, 7], [1, 5, 3, 8, 9, 7]]
		// console.log(this.formatPositionLayout(inputArrays))
		// console.log('🚀 ~ ToolDraw ~ layout ~ this.channelRoutes:', this.channelRoutes)
		const channelQueue = this.formatPositionLayout(this.channelRoutes)
		const queue = this.transpose(channelQueue)

		this.nodes = this.formatNodePosition(queue)
		// console.log('🚀 ~ ToolDraw ~ layout ~ this.nodes:', this.nodes)
	}

	/**
	 * 整理为有占位的二维数组，以便后续做输出展示
	 * @param rows 
	 * @returns 
	 */
	formatPositionLayout(rows) {
		const queue = rows.map((row) => [...row])
		// console.log('🚀 ~ ToolDraw ~ formatPositionLayout ~ rows:', rows)

		let flag = true

		while (flag) {
			flag = false

			loopAppend:
			for (let i = 0; i < queue.length; i++) {
				const row = queue[i]
				const other = queue.filter((r, k) => k !== i)
				let j = 0
				let prevInsert = true

				while (j < row.length) {
					const id = row[j]

					if (id === undefined) {
						j++
						continue
					}

					// 寻找其他行里面与当前 id 相同的元素的最大下标，如果存在，把当前元素调整到最大下标的位置，新增位置补充为 undefined
					const index = Math.max(-1, ...other.map((r) => r.indexOf(id)))

					if (j === index) {
						prevInsert = false
					}

					if (index > 0 && j < index) {
						row.splice(prevInsert ? 0 : j, 0, ...Array(index - j).fill(undefined))
						// j = index
						flag = true
						break loopAppend
					}

					j++
				}
			}
		}

		// console.table(queue)

		return queue
	}

	/**
	 * 根据已经整理好位置的数据，生成对应坐标
	 * @param queue 
	 * @returns 
	 */
	formatNodePosition(queue) {
		if (!queue.length) {
			return []
		}

		const rows = queue.map((q) => [...q])
		const positionRows= []
		const nodes = []
		const widthQueue = Array(queue[0].length).fill(0)
		let y = 0
		// console.log('🚀 ~ ToolDraw ~ formatNodePosition ~ rows:', rows)

		rows.forEach((row, i) => {
			positionRows[i] = []
			const currentRowSet = positionRows[i]
			let height = 0

			row.forEach((id, j) => {
				const node = this.nodeMap.get(id)

				// 每行循环中，如果当前位置没有添加过或者是占位符的情况加，追加元素
				// if (currentRowSet.at(-1) !== id || currentRowSet.at(-1) === undefined) {
				// if (!currentRowSet.includes(id) || currentRowSet.at(-1) === undefined) {
				//   currentRowSet.push(id)
				// }
				currentRowSet.push(!currentRowSet.includes(id) ? id : undefined)

				node && node.row++

				// 取每一行节点中当前列的最大宽度
				widthQueue[j] = Math.max(widthQueue[j], node?.width || 0)

				// 取当前行里元素的最大高度
				height = Math.max(height, node?.height || 0)
			})

			height += this.colPadding * 2

			// 配置每个节点的位置信息
			currentRowSet.forEach((id) => {
				const node = this.nodeMap.get(id)

				if (!node) {
					return
				}

				node.y = y + Math.floor((height - node.height) / 2)
			})

			// 为下一行初始化 y 轴的坐标
			y += height + this.colGap
			// console.log('🚀 ~ ToolDraw ~ currentRowSet.forEach ~ currentRowSet:', currentRowSet)
		})

		// console.log('🚀 ~ ToolDraw ~ formatNodePosition ~ positionRows:', positionRows, width)

		positionRows.forEach(row => {
			let x = 0
			let w = 0

			row.forEach((id, i) => {
				const node = this.nodeMap.get(id)

				let j = node ? node.row - 1 : 0

				w = this.rowGap * j

				// 根据元素所占的列数，计算元素的宽度
				while (j >= 0) {
					// console.log('🚀 ~ ToolDraw ~ row.forEach ~ width[i + j]:', width[i + j])
					// 这里的 200 是防止在 widthQueue 获取不到真实 width 时的默认宽度
					w += (widthQueue[i + j] || 200) + this.rowPadding * 2
					j--
				}
				// console.log('🚀 ~ ToolDraw ~ formatNodePosition ~ x:', x)

				if (node) {
					node.x = x + Math.floor((w - node.width) / 2)
					nodes.push(node)
				}
				// console.log('🚀 ~ ToolDraw ~ formatNodePosition ~ id, x, w:', id, x, w)

				// 为下一列初始化 x 轴的zuo'biao
				x += w + this.rowGap
			})
		})

		return nodes
	}

	// 把横向的二维数据转成纵向
	transpose(rows) {
		const routes = rows.map((row) => [...row])
		const queue = []

		let queueIndex = 0
		let hasRow = true

		while (hasRow) {
			hasRow = false
			queue[queueIndex] = Array(routes.length).fill(undefined)

			for (let index = 0; index < routes.length; index++) {
				const route = routes[index]
				queue[queueIndex][index] = route.shift()

				if (route.length) {
					hasRow = true
				}
			}

			queueIndex++
		}

		return queue
	}
}

export default ToolDraw